using System;
using System.Collections.Generic;

namespace SimpleCore.Pool
{
    /// <summary>
    /// 对象池
    /// 获取对象，池中没有时，可以自动创建
    /// 存入对象，超出池最大数量时，自动销毁
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Pool<T> where T : IPoolElement
    {
        public Pool(int size = 0, Func<T> create = null, Action<T> dispose = null)
        {
            _size = size;
        }

        public void SetCreateFunc(Func<T> create)
        {
            _createCallBack = create;
        }

        public void SetDisposeAction(Action<T> dispose)
        {
            _disposeCallBack = dispose;
        }

        public bool Push(T element)
        {
            bool allowPush = _size == 0 || _elements.Count < _size;
            if (allowPush)
            {
                _elements.Push(element);
                return true;
            }
            else
            {
                _disposeCallBack?.Invoke(element);
                return false;
            }
        }

        public bool TryPop(out T element)
        {
            if (_elements.Count > 0)
            {
                element = _elements.Pop();
                return true;
            }

            if (_createCallBack == null)
            {
                element = default;
                return false;
            }

            element = _createCallBack();
            
            return true;
        }

        public T Pop()
        {
            if (_elements.Count > 0)
            {
                return _elements.Pop();
            }

            if (_createCallBack == null)
            {
                return default;
            }

            return _createCallBack();
        }

        public void Clear()
        {
            while (_elements.Count > 0)
            {
                var element = _elements.Pop();
                _disposeCallBack?.Invoke(element);
            }
        }

        public int Size => _size;
        private int _size;

        public int CurrentSize => _elements.Count;
        
        Stack<T> _elements = new Stack<T>();
        private Func<T> _createCallBack;
        private Action<T> _disposeCallBack;
    }
}